package github.sf.fw.utils;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

public class StrUtil {
    /**
     * 经测试该方法的运行速度优于String.format,但该方法功能比较单一
     * 不支持转义
     */
    public static String format(String path, Object... args) {
        StringBuilder sb = new StringBuilder();
        if (args != null) {
            Iterator<Object> iterator = Arrays.stream(args).iterator();
            //0在{}外,1碰到{,2碰到},3维持状态不变
            int state = 0;
            char[] chars = path.toCharArray();
            for (char ch : chars) {
                //根据遇到的值变换状态
                if (ch == '{') {
                    state = 1;
                } else if (ch == '}') {
                    state = 2;
                }
                //状态转换
                if (state == 0) {
                    sb.append(ch);
                }
                if (state == 1) {
                    state = 3;
                }
                if (state == 2) {
                    if (iterator.hasNext()) {
                        sb.append(iterator.next());
                        state = 0;
                    } else {
                        throw new RuntimeException("{}和输入的变量数量不匹配");
                    }
                }
            }
        }
        return sb.toString();
    }


    /**
     * 支持转义
     */
    public static String format1(String path, Object... args) {
        StringBuilder sb = new StringBuilder();
        if (args != null) {
            Iterator<Object> iterator = Arrays.stream(args).iterator();
            //0在{}外,1碰到{,2碰到},3维持状态不变
            int state = 0;
            char[] chars = path.toCharArray();
            for (int i = 0; i < chars.length; i++) {
                char ch = chars[i];
                //根据遇到的值变换状态
                if (ch == '{' && (i == 0 || chars[i - 1] != '\\')) {
                    state = 1;
                } else if (ch == '}' && (i == 0 || chars[i - 1] != '\\')) {
                    state = 2;
                }
                //状态转换
                if (state == 0) {
                    sb.append(ch);
                }
                if (state == 1) {
                    state = 3;
                }
                if (state == 2) {
                    if (iterator.hasNext()) {
                        sb.append(iterator.next());
                        state = 0;
                    } else {
                        throw new RuntimeException("{}和输入的变量数量不匹配");
                    }
                }
            }
        }
        return sb.toString();
    }

    public static boolean isEmpty(String str) {
        return str == null || str.isEmpty();
    }

    public static boolean nonEmpty(String str) {
        return !isEmpty(str);
    }

    public static String pathJoin(String prefix, String suffix, Properties parameters) {
        StringBuilder url = new StringBuilder(withoutDuplicateJoin(prefix, suffix, "/"));
        if (parameters != null && parameters.size() > 0) {
            url.append("?");
            int count = 0;
            for (Map.Entry<Object, Object> propertyEntry : parameters.entrySet()) {
                if (count++ < parameters.size() - 1) {
                    url.append(propertyEntry.getKey()).append("=").append(propertyEntry.getValue()).append("&");
                } else {
                    url.append(propertyEntry.getKey()).append("=").append(propertyEntry.getValue());
                }
            }
        }
        return url.toString();
    }

    public static String withoutDuplicateJoin(String prefix, String suffix, String pathDelimiter) {
        if (isEmpty(prefix)) {
            return suffix;
        }
        if (isEmpty(suffix)) {
            return prefix;
        }
        int delimiterLen = pathDelimiter.length();
        if (prefix.endsWith(pathDelimiter)) {
            prefix = prefix.substring(0, prefix.length() - delimiterLen);
        }
        if (suffix.startsWith(pathDelimiter)) {
            return prefix + suffix;
        }
        return prefix + pathDelimiter + suffix;
    }

    public static boolean pathEq(String path1, String path2) {
        if (path1 == null || path2 == null) {
            return Objects.equals(path1, path2);
        }
        if (path1.startsWith("/")) {
            path1 = path1.substring(1);
        }
        if (path2.startsWith("/")) {
            path2 = path2.substring(1);
        }

        if (path1.endsWith("/")) {
            path1 = path1.substring(0, path1.length() - 1);
        }
        if (path2.endsWith("/")) {
            path2 = path2.substring(0, path2.length() - 1);
        }
        return Objects.equals(path1, path2);
    }

    public static boolean isNum(String realValue) {
        try {
            BigDecimal bigDecimal = new BigDecimal(realValue);
        } catch (NumberFormatException e) {
            return false;
        }
        return true;
    }

    public static String capitalize(String str) {
        if (isEmpty(str)) {
            return str;
        }
        char first = str.toCharArray()[0];
        return Character.toUpperCase(first) + str.substring(1);
    }

    /**
     * 将驼峰式命名的字符串转换为下划线大写方式。如果转换前的驼峰式命名的字符串为空，则返回空字符串。
     * 例如：HelloWorld->HELLO_WORLD
     *
     * @param name 转换前的驼峰式命名的字符串
     * @return 转换后下划线大写方式命名的字符串
     */
    public static String underscoreName(String name, boolean upperCase) {
        StringBuilder result = new StringBuilder();
        if (name != null && name.length() > 0) {
            // 将第一个字符处理成大写
            result.append(name.substring(0, 1).toUpperCase());
            // 循环处理其余字符
            for (int i = 1; i < name.length(); i++) {
                String s = name.substring(i, i + 1);
                // 在大写字母前添加下划线
                if (s.equals(s.toUpperCase()) && !Character.isDigit(s.charAt(0))) {
                    result.append("_");
                }
                // 其他字符直接转成大写
                if (upperCase) {
                    result.append(s.toUpperCase());
                } else {
                    result.append(s.toLowerCase());
                }
            }
        }
        return result.toString();
    }

    /**
     * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。
     * 例如：HELLO_WORLD->HelloWorld
     *
     * @param name 转换前的下划线大写方式命名的字符串
     * @return 转换后的驼峰式命名的字符串
     */
    public static String camelName(String name) {
        StringBuilder result = new StringBuilder();
        // 快速检查
        if (name == null || name.isEmpty()) {
            // 没必要转换
            return "";
        } else if (!name.contains("_")) {
            // 不含下划线，仅将首字母小写
            return name.substring(0, 1).toLowerCase() + name.substring(1);
        }
        // 用下划线将原始字符串分割
        String camels[] = name.split("_");
        for (String camel : camels) {
            // 跳过原始字符串中开头、结尾的下换线或双重下划线
            if (camel.isEmpty()) {
                continue;
            }
            // 处理真正的驼峰片段
            if (result.length() == 0) {
                // 第一个驼峰片段，全部字母都小写
                result.append(camel.toLowerCase());
            } else {
                // 其他的驼峰片段，首字母大写
                result.append(camel.substring(0, 1).toUpperCase());
                result.append(camel.substring(1).toLowerCase());
            }
        }
        return result.toString();
    }

    /**
     * 拼接路径
     *
     * @param p1 路径一
     * @param p2 路径二
     * @return 拼接后完整的路径
     */
    public static String fsCombine(String p1, String p2) {
        String temp1 = p1.replaceAll("[/\\\\]$", "");
        String temp2 = p2.replaceAll("^[/\\\\]", "");
        if (File.separator.equals("\\")) {
            temp1 = temp1.replaceAll("/", "\\\\");
            temp2 = temp2.replaceAll("/", "\\\\");
            return temp1 + "\\" + temp2;
        } else {
            temp1 = temp1.replaceAll("\\\\", "/");
            temp2 = temp2.replaceAll("\\\\", "/");
            return temp1 + "/" + temp2;
        }
    }

    /**
     * 返回字符串的最后{@code lineCount}行数据
     *
     * @param content   内容
     * @param lineCount 行数
     */
    public static String lastLine(String content, int lineCount) {
        if (isEmpty(content)) {
            return content;
        }
        int length = content.length();
        StringBuilder result = new StringBuilder();
        int count = 0;
        for (int i = length - 1; i >= 0 && count < lineCount; i--) {
            char ch = content.charAt(i);
            if (ch == '\n') {
                count++;
            }
            if (count < lineCount) {
                result.append(ch);
            }
        }
        result.reverse();
        return result.toString();
    }

    public static String lastLineInFile(String fileName, int lineCount) {
        List<String> strings = null;
        try {
            strings = Files.readAllLines(Paths.get(fileName));
            int size = strings.size();
            int remainLine = size - lineCount;
            int skipLine = Math.max(remainLine, 0);
            return strings.stream().skip(skipLine).limit(lineCount).collect(Collectors.joining("\n"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static String replaceVar(String content, Map<String, Object> variable) {
        if (isEmpty(content) || variable == null || variable.isEmpty()) {
            return content;
        }
//        String leftPattern = "\\$\\{";
//        String rightPattern = "\\}";
        for (Map.Entry<String, Object> entry : variable.entrySet()) {
//            String pattern = format1("\\$\\{{}\\}", entry.getKey());
            String pattern = "\\$\\{" + entry.getKey() + "\\}";
            content = content.replaceAll(pattern, entry.getValue().toString());
        }
        return content;
    }
}
